#!/usr/bin/env python
# coding=utf-8

import os
import sys
import json
import traceback

import oss2

from log import init, debug, info, warn, error
from utils import Singleton

status_code = "StatusCode"
message = "Message"
request_id = "RequestId"
bucket_name = "BucketName"
timeout = "Timeout"
buckets = "Buckets"
bucket_acl = "BucketAcl"
file_name = "FileName"
object = "Object"
upload_mode = "UploadMode"
upload_put_object = "PutObject"
upload_append_obj = "AppendObject"

class ALiYunOSSOperation(Singleton):

    def __init__(self, ak, secret, region_id, token=None):
        self.ak = ak
        self.secret = secret
        self.region_id = region_id
        self.endpoint = "https://oss-cn-%s.aliyuncs.com" % (self.region_id)
        self.token = token
        if self.token:
            self.auth = oss2.StsAuth(self.ak, self.secret, self.token)
        else:
            self.auth = oss2.Auth(self.ak, self.secret)
        self.bucket = None
        self.timeout = 30

    def CreateBucket(self, **kwargs):
        res = None
        try:
            if bucket_name not in kwargs:
                raise Exception("Failed to get bucket name, use %s=<bucket name> to pass in."
                                % (bucket_name))
            b_kwargs = {}
            if timeout in kwargs:
                b_kwargs["connect_timeout"] = kwargs[timeout]
            else:
                b_kwargs["connect_timeout"] = self.timeout

            self.bucket = oss2.Bucket(self.auth, self.endpoint, kwargs[bucket_name], **b_kwargs)
            self.bucket.create_bucket()
            res = {
                status_code: "200",
                message: "",
                request_id: ""
            }
        except Exception as ex:
            error(traceback.format_exc())
            error("Failed to create bucket due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: ""
            }

        return res

    def DeleteBucket(self, **kwargs):
        res = None
        try:
            if not self.bucket:
                self.bucket = oss2.Bucket(self.auth, self.endpoint,
                                          kwargs[bucket_name],
                                          connect_timeout=self.timeout)
            self.bucket.delete_bucket()
            res = {
                status_code: "200",
                message: "",
                request_id: ""
            }
        except Exception as ex:
            error(traceback.format_exc())
            error("Failed to delete bucket due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: ""
            }

        return res

    def GetAllBuckets(self, **kwargs):
        res = None
        try:
            service = oss2.Service(self.auth, self.endpoint)
            res = {
                status_code: "200",
                message: "",
                request_id: "",
                buckets: [b.name for b in oss2.BucketIterator(service)]
            }
        except Exception as ex:
            error(traceback.format_exc())
            error("Failed to get all buckets due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: ""
            }

        return res

    def GetBucketAttribute(self, **kwargs):
        res = None
        try:
            if not self.bucket:
                self.bucket = oss2.Bucket(self.auth, self.endpoint,
                                          kwargs[bucket_name],
                                          connect_timeout=self.timeout)
            acl = self.bucket.get_bucket_acl()
            res = {
                status_code: "200",
                message: "",
                request_id: "",
                bucket_acl: acl.acl
            }
        except Exception as ex:
            error(traceback.format_exc())
            error("Failed to get bucket attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: ""
            }

        return res

    def SetBucketAttribute(self, **kwargs):
        res = None
        try:
            if not self.bucket:
                self.bucket = oss2.Bucket(self.auth, self.endpoint,
                                          kwargs[bucket_name],
                                          connect_timeout=self.timeout)
            if bucket_acl in kwargs:
                # optional value: private public_r public_rw
                self.bucket.put_bucket_acl(kwargs[bucket_acl])

            res = {
                status_code: "200",
                message: "",
                request_id: ""
            }

        except Exception as ex:
            error(traceback.format_exc())
            error("Failed to set bucket attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: ""
            }

        return res

    def UploadObject2Oss(self, **kwargs):
        """
        上传对象到 oss2 中作为文件形式保存，支持如下的格式
        1. string 对象
        2. bytes 对象
        3. unicode 对象
        4. 文件对象
        5. 网络流 requests 的返回可迭代对象
        :param kwargs:
        :return:
        """
        res = None
        try:
            if file_name not in kwargs:
                raise Exception("Failed to get stored file name, use %s=<upload file name> to pass in." % (file_name))

            if object not in kwargs:
                raise Exception("Failed to get object to upload, use %s=<object> to pass in." % (object))

            # 指定上传模式：普通上传 PutObject 追加上传 AppendObject 文件断点续传 ResumableUpload
            # 分片上传 PartUpload
            upload_m = upload_put_object
            if upload_mode in kwargs:
                upload_m = kwargs[upload_m]

            if not self.bucket:
                self.bucket = oss2.Bucket(self.auth, self.endpoint,
                                          kwargs[bucket_name],
                                          connect_timeout=self.timeout)
            if upload_m == upload_put_object:
                # 普通上传
                self.bucket.put_object(kwargs[file_name], kwargs[object])
            elif upload_m == upload_append_obj:
                # 追加上传
                self.bucket.append_object(kwargs[file_name], kwargs[seek_pos], kwargs[object])
            elif upload_m == upload_resumable_file:
                # 断点续传
                oss2.resumable_upload(self.bucket, kwargs[file_name], kwargs[target_file_name])


        except Exception as ex:
            error(traceback.format_exc())
            error("Failed to upload content to file due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: ""
            }

        return res